use sqlite_wasm_rs::sqlite3_stmt;
use crate::db::dao::base_dao::Adder;
use crate::db::db::{Db, DbParamType};
use crate::db::pojo::pojo::ImCollect;
use crate::db::util::{db_get_enum, db_get_int64, db_get_string};
use crate::util::time::parse_to_time;

const SELECT_COLUMNS: &'static str = "id, serverId, userId, sessionId, messageId, labelIds, content, messageType, status, createTime, updateTime";

pub fn collect_inserts(db: Db, collects: &mut Vec<&mut ImCollect>) {
    if collects.is_empty() {
        return;
    }

    let sql = c"insert into im_collect(serverId, userId, messageId, sessionId, labelIds, content, messageType, status, createTime, updateTime)
        values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

    let mut params = vec![];
    for collect in collects.iter() {
        let mut param = vec![];
        param.push(DbParamType::OptionStr(collect.server_id.as_ref()));
        param.push(DbParamType::Str(&*collect.user_id));
        param.push(DbParamType::Str(&*collect.message_id));
        param.push(DbParamType::Str(&*collect.session_id));
        param.push(DbParamType::OptionStr(collect.label_ids.as_ref()));
        param.push(DbParamType::Str(&*collect.content));
        param.push(DbParamType::Byte(collect.message_type.clone() as i8));
        param.push(DbParamType::Byte(collect.status.clone() as i8));
        param.push(DbParamType::DateTime2(&collect.create_time));
        param.push(DbParamType::DateTime2(&collect.update_time));
        params.push(param);
    }

    log::info!("db collect params {:?}", params);
    let ids = db.inserts("collect inserts", sql, params);
    assert_eq!(ids.len(), collects.len());
    for (idx, id) in ids.into_iter().enumerate() {
        let collect = collects.get_mut(idx).unwrap();
        collect.id = Some(id);
    }
}

pub fn collect_updates(db: Db, collects: &mut Vec<&mut ImCollect>) {
    if collects.is_empty() {
        return;
    }
    let sql = "update im_collect set serverId = ?, messageType=?, content = ?, labelIds = ?, status =?, updateTime = ? where id = ?";
    let mut params = vec![];
    for collect in collects.iter() {
        let mut param = vec![];
        param.push(DbParamType::OptionStr(collect.server_id.as_ref()));
        param.push(DbParamType::Byte(collect.message_type.clone() as i8));
        param.push(DbParamType::Str(&*collect.content));
        param.push(DbParamType::OptionStr(collect.label_ids.as_ref()));
        param.push(DbParamType::Byte(collect.status.clone() as i8));
        param.push(DbParamType::DateTime2(&collect.update_time));
        param.push(DbParamType::Uint(collect.id.unwrap()));
        params.push(param);
    }
    log::info!("db collect update params: {:?}", params);
    db.batch_exec("collect updates", sql.to_string(), params);
}

pub fn query_collect_by_server_id(db: Db, user_id: String, server_id: String) -> Option<ImCollect> {
    let sql = format!("select {} from im_collect where userId=? and serverId = ?", SELECT_COLUMNS);
    let mut params = vec![];
    params.push(DbParamType::Str(&user_id));
    params.push(DbParamType::Str(&server_id));
    db.query_one("collect query", sql, params, Box::new(collect_wrap))
}

pub fn query_collect_by_key(db: Db, user_id: &str, session_id: &str, message_id: &str) -> Option<ImCollect> {
    let sql = format!("select {} from im_label where userId=? and sessionId = ? and messageId = ?", SELECT_COLUMNS);
    let mut params = vec![];
    params.push(DbParamType::Str(user_id));
    params.push(DbParamType::Str(session_id));
    params.push(DbParamType::Str(message_id));
    db.query_one("collect query2", sql.to_string(), params, Box::new(collect_wrap))
}

pub fn collect_total(db: Db)-> usize {
    let size = db.count("collect total", c"select count(*) from im_collect", Vec::new());
    log::info!("db collect count: {}", size);
    size
}



fn collect_wrap(stmt: *mut sqlite3_stmt) -> ImCollect {
    unsafe {
        let mut adder = Adder::new();
        let id = db_get_int64(stmt, adder.add());
        let server_id = db_get_string(stmt, adder.add());
        let user_id = db_get_string(stmt, adder.add()).unwrap();
        let session_id = db_get_string(stmt, adder.add()).unwrap();
        let message_id = db_get_string(stmt, adder.add()).unwrap();
        let label_ids = db_get_string(stmt, adder.add());
        let content = db_get_string(stmt, adder.add()).unwrap();
        let message_type = db_get_enum(stmt, adder.add());
        let status = db_get_enum(stmt, adder.add());
        let create_time_str = db_get_string(stmt, adder.add()).unwrap();
        let update_time_str = db_get_string(stmt, adder.add()).unwrap();

        ImCollect {
            id: Some(id),
            user_id,
            server_id,
            message_id,
            session_id,
            content,
            label_ids,
            message_type,
            status,
            create_time: parse_to_time(create_time_str),
            update_time: parse_to_time(update_time_str),
        }
    }
}